home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / web / nuweb / msdos / scraps.c < prev   
Encoding:
C/C++ Source or Header  |  1993-06-01  |  16.7 KB  |  543 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <ctype.h>
  4.  
  5. #ifndef FALSE
  6. #define FALSE 0
  7. #endif
  8. #ifndef TRUE
  9. #define TRUE (!0)
  10. #endif
  11. typedef struct scrap_node {
  12.   struct scrap_node *next;
  13.   int scrap;
  14. } Scrap_Node;
  15. typedef struct name {
  16.   char *spelling;
  17.   struct name *llink;
  18.   struct name *rlink;
  19.   Scrap_Node *defs;
  20.   Scrap_Node *uses;
  21.   int mark;
  22.   char tab_flag;
  23.   char indent_flag;
  24.   char debug_flag;
  25. } Name;
  26.  
  27. int tex_flag;      /* if FALSE, don't emit the .tex file */
  28. int output_flag;   /* if FALSE, don't emit the output files */
  29. int compare_flag;  /* if FALSE, overwrite without comparison */
  30. char *command_name;
  31. char *source_name;  /* name of the current file */
  32. int source_line;    /* current line in the source file */
  33. Name *file_names;
  34. Name *macro_names;
  35. Name *user_names;
  36.  
  37. void pass1();
  38. void write_tex();
  39. void write_files();
  40. void source_open(); /* pass in the name of the source file */
  41. int source_get();   /* no args; returns the next char or EOF */
  42. void init_scraps();
  43. int collect_scrap();
  44. int write_scraps();
  45. Name *collect_file_name();
  46. Name *collect_macro_name();
  47. Name *collect_scrap_name();
  48. Name *name_add();
  49. Name *prefix_add();
  50. char *save_string();
  51. void reverse_lists();
  52. void *arena_getmem();
  53. void arena_free();
  54.  
  55.  
  56. #define SLAB_SIZE 500
  57.  
  58. typedef struct slab {
  59.   struct slab *next;
  60.   char chars[SLAB_SIZE];
  61. } Slab;
  62. typedef struct {
  63.   char *file_name;
  64.   int file_line;
  65.   Slab *slab;
  66. } ScrapEntry;
  67. ScrapEntry *SCRAP[256];
  68.  
  69. #define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]
  70.  
  71. int scraps;
  72. void init_scraps()
  73. {
  74.   scraps = 1;
  75.   SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
  76. }
  77. typedef struct {
  78.   Slab *scrap;
  79.   int index;
  80. } Manager;
  81. static void push(c, manager)
  82.      char c;
  83.      Manager *manager;
  84. {
  85.   Slab *scrap = manager->scrap;
  86.   int index = manager->index;
  87.   scrap->chars[index++] = c;
  88.   if (index == SLAB_SIZE) {
  89.     Slab *new = (Slab *) arena_getmem(sizeof(Slab));
  90.     scrap->next = new;
  91.     manager->scrap = new;
  92.     index = 0;
  93.   }
  94.   manager->index = index;
  95. }
  96. static void pushs(s, manager)
  97.      char *s;
  98.      Manager *manager;
  99. {
  100.   while (*s)
  101.     push(*s++, manager);
  102. }
  103. int collect_scrap()
  104. {
  105.   Manager writer;
  106.   {
  107.     Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));
  108.     if ((scraps & 255) == 0)
  109.       SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
  110.     scrap_array(scraps).slab = scrap;
  111.     scrap_array(scraps).file_name = save_string(source_name);
  112.     scrap_array(scraps).file_line = source_line;
  113.     writer.scrap = scrap;
  114.     writer.index = 0;
  115.   }
  116.   {
  117.     int c = source_get();
  118.     while (1) {
  119.       switch (c) {
  120.         case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",
  121.                           command_name, scrap_array(scraps).file_name,
  122.                           scrap_array(scraps).file_line);
  123.                   exit(-1);
  124.         case '@': {
  125.                     c = source_get();
  126.                     switch (c) {
  127.                       case '@': pushs("@@", &writer);
  128.                                 c = source_get();
  129.                                 break;
  130.                       case '|': {
  131.                                   do {
  132.                                     char new_name[100];
  133.                                     char *p = new_name;
  134.                                     do 
  135.                                       c = source_get();
  136.                                     while (isspace(c));
  137.                                     if (c != '@') {
  138.                                       Name *name;
  139.                                       do {
  140.                                         *p++ = c;
  141.                                         c = source_get();
  142.                                       } while (c != '@' && !isspace(c));
  143.                                       *p = '\0';
  144.                                       name = name_add(&user_names, new_name);
  145.                                       if (!name->defs || name->defs->scrap != scraps) {
  146.                                         Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  147.                                         def->scrap = scraps;
  148.                                         def->next = name->defs;
  149.                                         name->defs = def;
  150.                                       }
  151.                                     }
  152.                                   } while (c != '@');
  153.                                   c = source_get();
  154.                                   if (c != '}') {
  155.                                     fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
  156.                                             command_name, c, source_name, source_line);
  157.                                     exit(-1);
  158.                                   }
  159.                                 }
  160.                       case '}': push('\0', &writer);
  161.                                 return scraps++;
  162.                       case '<': {
  163.                                   Name *name = collect_scrap_name();
  164.                                   {
  165.                                     char *s = name->spelling;
  166.                                     int len = strlen(s) - 1;
  167.                                     pushs("@<", &writer);
  168.                                     while (len > 0) {
  169.                                       push(*s++, &writer);
  170.                                       len--;
  171.                                     }
  172.                                     if (*s == ' ')
  173.                                       pushs("...", &writer);
  174.                                     else
  175.                                       push(*s, &writer);
  176.                                     pushs("@>", &writer);
  177.                                   }
  178.                                   {
  179.                                     if (!name->uses || name->uses->scrap != scraps) {
  180.                                       Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  181.                                       use->scrap = scraps;
  182.                                       use->next = name->uses;
  183.                                       name->uses = use;
  184.                                     }
  185.                                   }
  186.                                   c = source_get();
  187.                                 }
  188.                                 break;
  189.                       default : fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
  190.                                         command_name, c, source_name, source_line);
  191.                                 exit(-1);
  192.                     }
  193.                   }
  194.                   break;
  195.         default:  push(c, &writer);
  196.                   c = source_get();
  197.                   break;
  198.       }
  199.     }
  200.   }
  201. }
  202. static char pop(manager)
  203.      Manager *manager;
  204. {
  205.   Slab *scrap = manager->scrap;
  206.   int index = manager->index;
  207.   char c = scrap->chars[index++];
  208.   if (index == SLAB_SIZE) {
  209.     manager->scrap = scrap->next;
  210.     index = 0;
  211.   }
  212.   manager->index = index;
  213.   return c;
  214. }
  215. static Name *pop_scrap_name(manager)
  216.      Manager *manager;
  217. {
  218.   char name[100];
  219.   char *p = name;
  220.   int c = pop(manager);
  221.   while (TRUE) {
  222.     if (c == '@')
  223.       {
  224.         c = pop(manager);
  225.         if (c == '@') {
  226.           *p++ = c;
  227.           c = pop(manager);
  228.         }
  229.         else if (c == '>') {
  230.           if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
  231.             p[-3] = ' ';
  232.             p -= 2;
  233.           }
  234.           *p = '\0';
  235.           return prefix_add(¯o_names, name);
  236.         }
  237.         else {
  238.           fprintf(stderr, "%s: found an internal problem (1)\n", command_name);
  239.           exit(-1);
  240.         }
  241.       }
  242.     else {
  243.       *p++ = c;
  244.       c = pop(manager);
  245.     }
  246.   }
  247. }
  248. int write_scraps(file, defs, global_indent, indent_chars,
  249.                    debug_flag, tab_flag, indent_flag)
  250.      FILE *file;
  251.      Scrap_Node *defs;
  252.      int global_indent;
  253.      char *indent_chars;
  254.      char debug_flag;
  255.      char tab_flag;
  256.      char indent_flag;
  257. {
  258.   int indent = 0;
  259.   while (defs) {
  260.     {
  261.       char c;
  262.       Manager reader;
  263.       int line_number = scrap_array(defs->scrap).file_line;
  264.       if (debug_flag) {
  265.         fprintf(file, "\n#line %d \"%s\"\n",
  266.                 line_number, scrap_array(defs->scrap).file_name);
  267.         {
  268.           if (indent_flag) {
  269.             if (tab_flag)
  270.               for (indent=0; indent<global_indent; indent++)
  271.                 putc(' ', file);
  272.             else
  273.               for (indent=0; indent<global_indent; indent++)
  274.                 putc(indent_chars[indent], file);
  275.           }
  276.           indent = 0;
  277.         }
  278.       }
  279.       reader.scrap = scrap_array(defs->scrap).slab;
  280.       reader.index = 0;
  281.       c = pop(&reader);
  282.       while (c) {
  283.         switch (c) {
  284.           case '@':  {
  285.                        c = pop(&reader);
  286.                        switch (c) {
  287.                          case '@': putc(c, file);
  288.                                    indent_chars[global_indent + indent] = ' ';
  289.                                    indent++;
  290.                                    break;
  291.                          case '<': {
  292.                                      Name *name = pop_scrap_name(&reader);
  293.                                      if (name->mark) {
  294.                                        fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",
  295.                                                command_name, name->spelling);
  296.                                        exit(-1);
  297.                                      }
  298.                                      if (name->defs) {
  299.                                        name->mark = TRUE;
  300.                                        indent = write_scraps(file, name->defs, global_indent + indent,
  301.                                                              indent_chars, debug_flag, tab_flag, indent_flag);
  302.                                        indent -= global_indent;
  303.                                        name->mark = FALSE;
  304.                                      }
  305.                                      else if (!tex_flag)
  306.                                        fprintf(stderr, "%s: macro never defined <%s>\n",
  307.                                                command_name, name->spelling);
  308.                                    }
  309.                                    if (debug_flag) {
  310.                                      fprintf(file, "\n#line %d \"%s\"\n",
  311.                                              line_number, scrap_array(defs->scrap).file_name);
  312.                                      {
  313.                                        if (indent_flag) {
  314.                                          if (tab_flag)
  315.                                            for (indent=0; indent<global_indent; indent++)
  316.                                              putc(' ', file);
  317.                                          else
  318.                                            for (indent=0; indent<global_indent; indent++)
  319.                                              putc(indent_chars[indent], file);
  320.                                        }
  321.                                        indent = 0;
  322.                                      }
  323.                                    }
  324.                                    break;
  325.                          default:  /* ignore, since we should already have a warning */
  326.                                    break;
  327.                        }
  328.                      }
  329.                      break;
  330.           case '\n': putc(c, file);
  331.                      line_number++;
  332.                      {
  333.                        if (indent_flag) {
  334.                          if (tab_flag)
  335.                            for (indent=0; indent<global_indent; indent++)
  336.                              putc(' ', file);
  337.                          else
  338.                            for (indent=0; indent<global_indent; indent++)
  339.                              putc(indent_chars[indent], file);
  340.                        }
  341.                        indent = 0;
  342.                      }
  343.                      break;
  344.           case '\t': {
  345.                        if (tab_flag)
  346.                          {
  347.                            int delta = 8 - (indent % 8);
  348.                            indent += delta;
  349.                            while (delta > 0) {
  350.                              putc(' ', file);
  351.                              delta--;
  352.                            }
  353.                          }
  354.                        else {
  355.                          putc('\t', file);
  356.                          indent_chars[global_indent + indent] = '\t';
  357.                          indent++;
  358.                        }
  359.                      }
  360.                      break;
  361.           default:   putc(c, file);
  362.                      indent_chars[global_indent + indent] = ' ';
  363.                      indent++;
  364.                      break;
  365.         }
  366.         c = pop(&reader);
  367.       }
  368.     }
  369.     defs = defs->next;
  370.   }
  371.   return indent + global_indent;
  372. }
  373.  
  374. typedef struct name_node {
  375.   struct name_node *next;
  376.   Name *name;
  377. } Name_Node;
  378.  
  379. typedef struct goto_node {
  380.   struct goto_node *next;       /* next goto node with same depth */
  381.   struct goto_node *fail;
  382.   struct move_node *moves;
  383.   Name_Node *output;
  384. } Goto_Node;
  385.  
  386. typedef struct move_node {
  387.   struct move_node *next;
  388.   Goto_Node *state;
  389.   char c;
  390. } Move_Node;
  391.  
  392. static Goto_Node *root[128];
  393. static int max_depth;
  394. static Goto_Node **depths;
  395. static Goto_Node *goto_lookup(c, g)
  396.      char c;
  397.      Goto_Node *g;
  398. {
  399.   Move_Node *m = g->moves;
  400.   while (m && m->c != c)
  401.     m = m->next;
  402.   if (m)
  403.     return m->state;
  404.   else
  405.     return NULL;
  406. }
  407.  
  408. static void build_gotos();
  409.  
  410. void search()
  411. {
  412.   int i;
  413.   for (i=0; i<128; i++)
  414.     root[i] = NULL;
  415.   max_depth = 10;
  416.   depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));
  417.   for (i=0; i<max_depth; i++)
  418.     depths[i] = NULL;
  419.   build_gotos(user_names);
  420.   {
  421.     int depth;
  422.     for (depth=1; depth<max_depth; depth++) {
  423.       Goto_Node *r = depths[depth];
  424.       while (r) {
  425.         Move_Node *m = r->moves;
  426.         while (m) {
  427.           char a = m->c;
  428.           Goto_Node *s = m->state;
  429.           Goto_Node *state = r->fail;
  430.           while (state && !goto_lookup(a, state))
  431.             state = state->fail;
  432.           if (state)
  433.             s->fail = goto_lookup(a, state);
  434.           else
  435.             s->fail = root[a];
  436.           if (s->fail) {
  437.             Name_Node *p = s->fail->output;
  438.             while (p) {
  439.               Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));
  440.               q->name = p->name;
  441.               q->next = s->output;
  442.               s->output = q;
  443.               p = p->next;
  444.             }
  445.           }
  446.           m = m->next;
  447.         }
  448.         r = r->next;
  449.       }
  450.     }
  451.   }
  452.   {
  453.     for (i=1; i<scraps; i++) {
  454.       char c;
  455.       Manager reader;
  456.       Goto_Node *state = NULL;
  457.       reader.scrap = scrap_array(i).slab;
  458.       reader.index = 0;
  459.       c = pop(&reader);
  460.       while (c) {
  461.         while (state && !goto_lookup(c, state))
  462.           state = state->fail;
  463.         if (state)
  464.           state = goto_lookup(c, state);
  465.         else
  466.           state = root[c];
  467.         if (state && state->output) {
  468.           Name_Node *p = state->output;
  469.           do {
  470.             Name *name = p->name;
  471.             if (!name->uses || name->uses->scrap != i) {
  472.               Scrap_Node *new_use =
  473.                   (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  474.               new_use->scrap = i;
  475.               new_use->next = name->uses;
  476.               name->uses = new_use;
  477.             }
  478.             p = p->next;
  479.           } while (p);
  480.         }
  481.         c = pop(&reader);
  482.       }
  483.     }
  484.   }
  485. }
  486. static void build_gotos(tree)
  487.      Name *tree;
  488. {
  489.   while (tree) {
  490.     {
  491.       int depth = 2;
  492.       char *p = tree->spelling;
  493.       char c = *p++;
  494.       Goto_Node *q = root[c];
  495.       if (!q) {
  496.         q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
  497.         root[c] = q;
  498.         q->moves = NULL;
  499.         q->fail = NULL;
  500.         q->moves = NULL;
  501.         q->output = NULL;
  502.         q->next = depths[1];
  503.         depths[1] = q;
  504.       }
  505.       while (c = *p++) {
  506.         Goto_Node *new = goto_lookup(c, q);
  507.         if (!new) {
  508.           Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));
  509.           new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
  510.           new->moves = NULL;
  511.           new->fail = NULL;
  512.           new->moves = NULL;
  513.           new->output = NULL;
  514.           new_move->state = new;
  515.           new_move->c = c;
  516.           new_move->next = q->moves;
  517.           q->moves = new_move;
  518.           if (depth == max_depth) {
  519.             int i;
  520.             Goto_Node **new_depths =
  521.                 (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));
  522.             max_depth = 2 * depth;
  523.             for (i=0; i<depth; i++)
  524.               new_depths[i] = depths[i];
  525.             depths = new_depths;
  526.             for (i=depth; i<max_depth; i++)
  527.               depths[i] = NULL;
  528.           }
  529.           new->next = depths[depth];
  530.           depths[depth] = new;
  531.         }
  532.         q = new;
  533.         depth++;
  534.       }
  535.       q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));
  536.       q->output->next = NULL;
  537.       q->output->name = tree;
  538.     }
  539.     build_gotos(tree->rlink);
  540.     tree = tree->llink;
  541.   }
  542. }
  543.